\newcommand{\PPC}{\InSqBrackets{\IT{PowerPC(tm) Microprocessor Family: The Programming Environments for 32-Bit Microprocessors}, (2000)}\footnote{\AlsoAvailableAs \url{http://yurichev.com/mirrors/PowerPC/6xx_pem.pdf}}}

\newcommand{\PPCABI}{[Steve Zucker, SunSoft and Kari Karhi, IBM, \IT{SYSTEM V APPLICATION BINARY INTERFACE: PowerPC Processor Supplement}, (1995)]\footnote{\AlsoAvailableAs \url{http://yurichev.com/mirrors/PowerPC/elfspec_ppc.pdf}}}

\subsection{Пример \#1: MacOS Classic и PowerPC}

\myindex{PowerPC}
\myindex{Mac OS Classic}
Вот пример программы для MacOS Classic
\footnote{MacOS перед тем как перейти на UNIX}, для PowerPC.
Компания, разработавшая этот продукт, давно исчезла, так что (легальный) пользователь
боялся того что донгла может сломаться.

Если запустить программу без подключенной донглы, можно увидеть окно с надписью

"Invalid Security Device".
Мне повезло потому что этот текст можно было легко найти внутри исполняемого файла.

Представим, что мы не знакомы ни с Mac OS Classic, ни с PowerPC, но всё-таки попробуем.

\ac{IDA} открывает исполняемый файл легко, показывая его тип как
 
"PEF (Mac OS or Be OS executable)" (действительно, это стандартный тип файлов в Mac OS Classic).

В поисках текстовой строки с сообщение об ошибке, мы попадаем на этот фрагмент кода:

\lstinputlisting[style=customasmPPC]{examples/dongles/1/1.lst}

\myindex{ARM}
\myindex{MIPS}
Да, это код PowerPC.
Это очень типичный процессор для \ac{RISC} 1990-х.
Каждая инструкция занимает 4 байта (как и в MIPS и ARM) и их имена немного похожи на имена 
инструкций MIPS.

\TT{check1()} это имя которое мы дадим этой функции немного позже.
\TT{BL} это инструкция \IT{Branch Link} 
т.е. предназначенная для вызова подпрограмм.
Самое важное место --- это инструкция \ac{BNE}, срабатывающая, если проверка наличия донглы прошла
успешно, либо не срабатывающая в случае ошибки: и тогда адрес текстовой строки с сообщением об ошибке
будет загружен в регистр r3 для последующей передачи в функцию отображения диалогового окна.

Из \PPCABI мы узнаем, что регистр r3 используется для возврата
значений (и еще r4 если значение 64-битное).

\myindex{x86!\Instructions!MOVZX}
Еще одна, пока что неизвестная инструкция \TT{CLRLWI}. 
Из \PPC мы узнаем, что эта инструкция одновременно и очищает и загружает. 
В нашем случае, она очищает 24 старших бита из значения в r3 и записывает всё это в r0, 
так что это аналог \MOVZX в x86 (\myref{movzx}),
но также устанавливает флаги, так что \ac{BNE} 
может проверить их потом.

Посмотрим внутрь \TT{check1()}:

\lstinputlisting[style=customasmPPC]{examples/dongles/1/check1.lst}

Как можно увидеть в \ac{IDA}, эта функция вызывается из многих мест в программе, но только значение
в регистре r3 проверяется сразу после каждого вызова.
\myindex{thunk-функции}
Всё что эта функция делает это только вызывает другую функцию, так что это \gls{thunk function}: 
здесь присутствует и пролог функции и эпилог, но регистр r3 не трогается, так что \TT{checkl()} 
возвращает то, что возвращает \TT{check2()}.

\ac{BLR} это похоже возврат из функции, но так как IDA делает всю разметку функций автоматически,
наверное, мы можем пока не интересоваться этим.
Так как это типичный \ac{RISC}, похоже, подпрограммы вызываются, используя \gls{link register}, точно как в ARM.

Функция \TT{check2()} более сложная:

\lstinputlisting[style=customasmPPC]{examples/dongles/1/check2.lst}

\myindex{USB}
Снова повезло: имена некоторых функций оставлены в исполняемом файле
(в символах в отладочной секции? Трудно сказать до тех пор, пока мы не знакомы с этим форматом файлов,
может быть это что-то вроде PE-экспортов (\myref{PE_exports_imports}))?\\
Как например \TT{.RBEFINDNEXT()} and \TT{.RBEFINDFIRST()}.

В итоге, эти функции вызывают другие функции с именами вроде \TT{.GetNextDeviceViaUSB()}, 
\TT{.USBSendPKT()},
так что они явно работают с каким-то USB-устройством.

Тут даже есть функция с названием 
\TT{.GetNextEve3Device()} --- звучит знакомо, в 1990-х годах была донгла Sentinel Eve3 
для ADB-порта (присутствующих на Макинтошах).

В начале посмотрим на то как устанавливается регистр r3 одновременно игнорируя всё остальное.
Мы знаем, что \q{хорошее} значение в r3 должно быть не нулевым, а нулевой r3 приведет
к выводу диалогового окна с сообщением об ошибке.

В функции имеются две инструкции \TT{li \%r3, 1} 
и одна \TT{li \%r3, 0} 
(\IT{Load Immediate}, т.е. загрузить значение в регистр).
Самая первая инструкция находится на 
\TT{0x001186B0} --- и честно говоря, трудно заранее понять, что это означает.

А вот то что мы видим дальше понять проще: 
вызывается \TT{.RBEFINDFIRST()} и в случае ошибки, 0 будет записан в r3
и мы перейдем на \IT{exit}, а иначе будет вызвана функция \TT{check3()} --- если и она будет
выполнена с ошибкой, будет вызвана
\TT{.RBEFINDNEXT()} вероятно, для поиска другого USB-устройства.

N.B.: \TT{clrlwi. \%r0, \%r3, 16} это аналог того что мы уже видели, но она очищает 16 старших бит,
т.е., \\
\TT{.RBEFINDFIRST()} вероятно возвращает 16-битное значение.

\TT{B} (означает \IT{branch}) --- безусловный переход.

\ac{BEQ} это обратная инструкция от \ac{BNE}.

Посмотрим на \TT{check3()}:

\lstinputlisting[style=customasmPPC]{examples/dongles/1/check3.lst}

Здесь много вызовов \TT{.RBEREAD()}. 
Эта функция, должно быть, читает какие-то значения из донглы, которые потом сравниваются здесь при помощи \TT{CMPLWI}.

Мы также видим в регистр r3 записывается перед каждым вызовом \TT{.RBEREAD()} 
одно из этих значений: 0, 1, 8, 0xA, 0xB, 0xC, 0xD, 4, 5.
Вероятно адрес в памяти или что-то в этом роде?

Да, действительно, если погуглить имена этих функций, можно легко найти документацию к Sentinel Eve3!

Hаверное, уже и не нужно изучать остальные инструкции PowerPC: всё что делает эта функция это просто
вызывает \TT{.RBEREAD()}, сравнивает его результаты с константами и возвращает 1 если результат сравнения положительный или 0 в другом случае.

Всё ясно: \TT{check1()} должна всегда возвращать 1 или иное ненулевое значение.
Но так как мы не очень уверены в своих знаниях инструкций PowerPC, будем осторожны и пропатчим переходы в \TT{check2} на адресах
\TT{0x001186FC} и \TT{0x00118718}.

На \TT{0x001186FC} мы записываем байты 0x48 и 0 таким образом превращая инструкцию \ac{BEQ} 
в инструкцию \TT{B} (безусловный переход):
мы можем заметить этот опкод прямо в коде даже без обращения к \PPC.

На \TT{0x00118718} мы записываем байт 0x60 и еще 3 нулевых байта,
таким образом превращая её в инструкцию
\ac{NOP}:
Этот опкод мы также можем подсмотреть прямо в коде.

И всё заработало без подключенной донглы.

Резюмируя, такие простые модификации можно делать в \ac{IDA} даже с минимальными знаниями
ассемблера.

